#include <cmath>

class ProjectMatrix {

public:
	float matrix[4][4];

	ProjectMatrix() {
		matrix[0][0] = 1.0f; matrix[0][1] = 0.0f; matrix[0][2] = 0.0f; matrix[0][3] = 0.0f;
		matrix[1][0] = 0.0f; matrix[1][1] = 1.0f; matrix[1][2] = 0.0f; matrix[1][3] = 0.0f;
		matrix[2][0] = 0.0f; matrix[2][1] = 0.0f; matrix[2][2] = 1.0f; matrix[2][3] = 0.0f;
		matrix[3][0] = 0.0f; matrix[3][1] = 0.0f; matrix[3][2] = 0.0f; matrix[3][3] = 1.0f;
	}

	void ortho(float left, float right, float top, float bottom, float near, float far) {
		matrix[0][0] = 2.0f / (right - left);
		matrix[1][1] = 2.0f / (top - bottom);
		matrix[2][2] = 2.0f / (near - far);

		matrix[0][3] = (right + left) / (left - right);
		matrix[1][3] = (top + bottom) / (bottom - top);
		matrix[2][3] = (near + far) / (near -far);

		matrix[0][1] = 0.0f; matrix[0][2] = 0.0f;
		matrix[1][0] = 0.0f; matrix[1][2] = 0.0f;
		matrix[2][0] = 0.0f; matrix[2][1] = 0.0f;
		matrix[3][0] = 0.0f; matrix[3][1] = 0.0f; 
		matrix[3][2] = 0.0f; matrix[3][3] = 1.0f;
	}
	
	void frustum(float left, float right, float top, float bottom, float near, float far) {
		matrix[0][0] = 2.0f * near / (right - left);
		matrix[0][1] = 0.0f;
		matrix[0][2] = (right + left) / (right - left);
		matrix[0][3] = 0.0f;

		matrix[1][0] = 0.0f;
		matrix[1][1] = 2.0f * near / (top - bottom);
		matrix[1][2] = (top + bottom) / (top - bottom);
		matrix[1][3] = 0.0f;

		matrix[2][2] = 0.0f;
		matrix[0][3] = 0.0f;
		matrix[1][3] = (far + near) / (near - far);
		matrix[2][3] = 2 * far * near / (near -far);

		matrix[3][0] = 0.0f;
		matrix[3][1] = 0.0f;
		matrix[3][2] = -1.0f;
		matrix[3][3] = 0.0f;
	}

	void perspective(float angle, float aspect, float near, float far) {
		float top = near * tan(angle / 2);
		float bottom = - top;
		float right = top * aspect;
		float left = -right;

		matrix[0][0] = 2.0f * near / (right - left);
		matrix[0][1] = 0.0f;
		matrix[0][2] = (right + left) / (right - left);
		matrix[0][3] = 0.0f;

		matrix[1][0] = 0.0f;
		matrix[1][1] = 2.0f * near / (top - bottom);
		matrix[1][2] = (top + bottom) / (top - bottom);
		matrix[1][3] = 0.0f;

		matrix[2][2] = 0.0f;
		matrix[0][3] = 0.0f;
		matrix[1][3] = (far + near) / (near - far);
		matrix[2][3] = 2 * far * near / (near -far);

		matrix[3][0] = 0.0f;
		matrix[3][1] = 0.0f;
		matrix[3][2] = -1.0f;
		matrix[3][3] = 0.0f;
	}
};